import java.util.Random;


public class opp4a_stigma {
	
	//define tables for sorting
	static Integer unsortedTable20[] = new Integer[20];
	static Integer unsortedTable32000[] = new Integer[32000];
	static Integer unsortedTable64000[] = new Integer[64000];
	static Integer unsortedTable128000[] = new Integer[128000];
	
	static long startTime = System.nanoTime();
	static long endTime;
	static long durationNano;
	static long durationMilli;
	static long durationSec;
	static long durationMin;
	
	static boolean doPrintouts = true;
	
	//baselines using n=32000
	static int numberOfBaselineRuns = 10;
	
	static long sorteringVedInsetting_baseline = 0;
	static double sorteringVedInsetting_cvalue = 0;
	static long sorteringVedInsetting_result64000 = 0;
	static long sorteringVedInsetting_result128000 = 0;
	
	static long utvalgsSortering_baseline = 0;
	static double utvalgsSortering_cvalue = 0;
	static long utvalgsSortering_result64000 = 0;
	static long utvalgsSortering_result128000 = 0;
	
	static long bobleSort_baseline = 0;
	static double bobleSort_cvalue = 0;
	static long bobleSort_result64000 = 0;
	static long bobleSort_result128000 = 0;
	
	static long kvikkSort_baseline = 0;
	static double kvikkSort_cvalue = 0;
	static long kvikkSort_result64000 = 0;
	static long kvikkSort_result128000 = 0;
	
	static long fletteSorter_baseline = 0;
	static double fletteSorter_cvalue = 0;
	static long fletteSorter_result64000 = 0;
	static long fletteSorter_result128000 = 0;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		@SuppressWarnings("rawtypes")
		SorteringOgSoking soking = new SorteringOgSoking();
		
//		//Fill tables with random Integer Objects
//		randomizeTables();
//		
//		//Do tests on the 20-length table
//		System.out.println("table contents before sorting");
//		printTable20();
//		System.out.println();
//		
//		System.out.println("results of sortering ved innsetting");
//		startTimer();
//		soking.sorteringVedInsetting(unsortedTable20);
//		stopTimer();
//		printTable20();
//		System.out.println();
//		
//		randomizeTables();
//		System.out.println("results of utvalgssortering");
//		startTimer();
//		soking.utvalgsSortering(unsortedTable20);
//		stopTimer();
//		printTable20();
//		System.out.println();
//		
//		randomizeTables();
//		System.out.println("results of boblesortering");
//		startTimer();
//		soking.bobleSort(unsortedTable20);
//		stopTimer();
//		printTable20();
//		System.out.println();
//		
//		randomizeTables();
//		System.out.println("results of kvikksort");
//		startTimer();
//		soking.kvikkSort(unsortedTable20,0,unsortedTable20.length-1);
//		stopTimer();
//		printTable20();
//		System.out.println();
//		
//		randomizeTables();
//		System.out.println("results of flettesorter");
//		startTimer();
//		soking.fletteSorter(unsortedTable20,0,unsortedTable20.length-1);
//		stopTimer();
//		printTable20();
//		System.out.println();
		
		//set baselines (using n=32000)
		
		//SORTERING VED INSETTING
		System.out.println("Setting baselines using n=32000");
		System.out.println();
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.sorteringVedInsetting(unsortedTable32000);
			stopTimer();
			sorteringVedInsetting_baseline = sorteringVedInsetting_baseline + durationNano;
		}
		sorteringVedInsetting_baseline = sorteringVedInsetting_baseline/numberOfBaselineRuns;
		sorteringVedInsetting_cvalue = (double) sorteringVedInsetting_baseline / (32*32);
		System.out.println("---------------------");
		System.out.println("SorteringVedInsetting average:");
		System.out.println(sorteringVedInsetting_baseline/1000000000+" sec");
		System.out.println(sorteringVedInsetting_baseline/1000000+" ms");
		System.out.println(sorteringVedInsetting_baseline+" ns");
		System.out.println("---------------------");
		System.out.println();
		
		
		//UTVALGSSORTERING
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.utvalgsSortering(unsortedTable32000);
			stopTimer();
			utvalgsSortering_baseline = utvalgsSortering_baseline + durationNano;
		}
		utvalgsSortering_baseline = utvalgsSortering_baseline/numberOfBaselineRuns;
		utvalgsSortering_cvalue =  (double) utvalgsSortering_baseline / (32*32);
		System.out.println("---------------------");
		System.out.println("utvalgsSortering average:");
		System.out.println(utvalgsSortering_baseline/1000000000+" sec");
		System.out.println(utvalgsSortering_baseline/1000000+" ms");
		System.out.println(utvalgsSortering_baseline+" ns");
		System.out.println("---------------------");
		System.out.println();
		
		//BOBLESORTERING
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.bobleSort(unsortedTable32000);
			stopTimer();
			bobleSort_baseline = bobleSort_baseline + durationNano;
		}
		bobleSort_baseline = bobleSort_baseline/numberOfBaselineRuns;
		bobleSort_cvalue = (double) bobleSort_baseline / (32*32);
		System.out.println("---------------------");
		System.out.println("bobleSort average:");
		System.out.println(bobleSort_baseline/1000000000+" sec");
		System.out.println(bobleSort_baseline/1000000+" ms");
		System.out.println(bobleSort_baseline+" ns");
		System.out.println("---------------------");
		System.out.println();
		
		//KVIKKSORT
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.kvikkSort(unsortedTable32000,0,unsortedTable32000.length-1);
			stopTimer();
			kvikkSort_baseline = kvikkSort_baseline + durationNano;
		}
		kvikkSort_baseline = kvikkSort_baseline/numberOfBaselineRuns;
		kvikkSort_cvalue = (double) kvikkSort_baseline / (32000 * (Math.log(32000)/Math.log(2)));
		System.out.println("---------------------");
		System.out.println("kvikkSort average:");
		System.out.println(kvikkSort_baseline/1000000000+" sec");
		System.out.println(kvikkSort_baseline/1000000+" ms");
		System.out.println(kvikkSort_baseline+" ns");
		System.out.println("---------------------");
		System.out.println();
		
		//FLETTESORTER
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.fletteSorter(unsortedTable32000,0,unsortedTable32000.length-1);
			stopTimer();
			fletteSorter_baseline = fletteSorter_baseline + durationNano;
		}
		fletteSorter_baseline = fletteSorter_baseline/numberOfBaselineRuns;
		fletteSorter_cvalue = (double) fletteSorter_baseline / (32000 * (Math.log(32000)/Math.log(2)));
		System.out.println("---------------------");
		System.out.println("fletteSorter average:");
		System.out.println(fletteSorter_baseline/1000000000+" sec");
		System.out.println(fletteSorter_baseline/1000000+" ms");
		System.out.println(fletteSorter_baseline+" ns");
		System.out.println("---------------------");
		System.out.println();
		
		System.out.println("--------------------------------------------------");
		System.out.println("BASELINE COMPLETE");
		System.out.println("--------------------------------------------------");

		//Comparing SorteringVedInsetting operation sizes
		System.out.println("--------------------------------------------------");
		System.out.println("SORTERINGVEDINSETTING");
		System.out.println("--------------------------------------------------");
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.sorteringVedInsetting(unsortedTable64000);
			stopTimer();
			sorteringVedInsetting_result64000 = sorteringVedInsetting_result64000 + durationNano;
		}
		sorteringVedInsetting_result64000 = sorteringVedInsetting_result64000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average sorteringVedInsetting results for 64000:");
		System.out.println(sorteringVedInsetting_result64000/1000000000+" sec");
		System.out.println(sorteringVedInsetting_result64000/1000000+" ms");
		System.out.println(sorteringVedInsetting_result64000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(64000^2)):");
		System.out.println("cvalue is " + sorteringVedInsetting_cvalue);
		double calculatedDurationNano = sorteringVedInsetting_cvalue * (64*64);
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.sorteringVedInsetting(unsortedTable128000);
			stopTimer();
			sorteringVedInsetting_result128000 = sorteringVedInsetting_result128000 + durationNano;
		}
		sorteringVedInsetting_result128000 = sorteringVedInsetting_result128000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average sorteringVedInsetting results for 128000:");
		System.out.println(sorteringVedInsetting_result128000/1000000000+" sec");
		System.out.println(sorteringVedInsetting_result128000/1000000+" ms");
		System.out.println(sorteringVedInsetting_result128000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(128000^2)):");
		System.out.println("cvalue is " + sorteringVedInsetting_cvalue);
		calculatedDurationNano = sorteringVedInsetting_cvalue * (128*128);
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		//Comparing utvalgsSortering operation sizes
		System.out.println("--------------------------------------------------");
		System.out.println("UTVALGSSORTERING");
		System.out.println("--------------------------------------------------");
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.utvalgsSortering(unsortedTable64000);
			stopTimer();
			utvalgsSortering_result64000 = utvalgsSortering_result64000 + durationNano;
		}
		utvalgsSortering_result64000 = utvalgsSortering_result64000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average utvalgssortering results for 64000:");
		System.out.println(utvalgsSortering_result64000/1000000000+" sec");
		System.out.println(utvalgsSortering_result64000/1000000+" ms");
		System.out.println(utvalgsSortering_result64000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(64000^2)):");
		System.out.println("cvalue is " + utvalgsSortering_cvalue);
		calculatedDurationNano = utvalgsSortering_cvalue * (64*64);
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.utvalgsSortering(unsortedTable128000);
			stopTimer();
			utvalgsSortering_result128000 = utvalgsSortering_result128000 + durationNano;
		}
		utvalgsSortering_result128000 = utvalgsSortering_result128000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average utvalgssortering results for 128000:");
		System.out.println(utvalgsSortering_result128000/1000000000+" sec");
		System.out.println(utvalgsSortering_result128000/1000000+" ms");
		System.out.println(utvalgsSortering_result128000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(128000^2)):");
		System.out.println("cvalue is " + utvalgsSortering_cvalue);
		calculatedDurationNano = utvalgsSortering_cvalue * (128*128);
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		//Comparing bobleSort operation sizes
		System.out.println("--------------------------------------------------");
		System.out.println("BOBLESORT");
		System.out.println("--------------------------------------------------");
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.bobleSort(unsortedTable64000);
			stopTimer();
			bobleSort_result64000 = bobleSort_result64000 + durationNano;
		}
		bobleSort_result64000 = bobleSort_result64000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average bobleSort results for 64000:");
		System.out.println(bobleSort_result64000/1000000000+" sec");
		System.out.println(bobleSort_result64000/1000000+" ms");
		System.out.println(bobleSort_result64000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(64000^2)):");
		System.out.println("cvalue is " + bobleSort_cvalue);
		calculatedDurationNano = bobleSort_cvalue * (64*64);
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.bobleSort(unsortedTable128000);
			stopTimer();
			bobleSort_result128000 = bobleSort_result128000 + durationNano;
		}
		bobleSort_result128000 = bobleSort_result128000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average bobleSort results for 128000:");
		System.out.println(bobleSort_result128000/1000000000+" sec");
		System.out.println(bobleSort_result128000/1000000+" ms");
		System.out.println(bobleSort_result128000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(128000^2)):");
		System.out.println("cvalue is " + bobleSort_cvalue);
		calculatedDurationNano = bobleSort_cvalue * (128*128);
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		//Comparing kvikkSort operation sizes
		System.out.println("--------------------------------------------------");
		System.out.println("KVIKKSORT");
		System.out.println("--------------------------------------------------");
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.kvikkSort(unsortedTable64000,0,unsortedTable64000.length-1);
			stopTimer();
			kvikkSort_result64000 = kvikkSort_result64000 + durationNano;
		}
		kvikkSort_result64000 = kvikkSort_result64000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average kvikkSort results for 64000:");
		System.out.println(kvikkSort_result64000/1000000000+" sec");
		System.out.println(kvikkSort_result64000/1000000+" ms");
		System.out.println(kvikkSort_result64000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(64000 * log2 64000)):");
		System.out.println("cvalue is " + kvikkSort_cvalue);
		
		calculatedDurationNano = kvikkSort_cvalue * (64000 * (Math.log(64000)/Math.log(2)));
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.kvikkSort(unsortedTable128000,0,unsortedTable128000.length-1);
			stopTimer();
			kvikkSort_result128000 = kvikkSort_result128000 + durationNano;
		}
		kvikkSort_result128000 = kvikkSort_result128000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average kvikkSort results for 128000:");
		System.out.println(kvikkSort_result128000/1000000000+" sec");
		System.out.println(kvikkSort_result128000/1000000+" ms");
		System.out.println(kvikkSort_result128000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(128000 * log 128000)):");
		System.out.println("cvalue is " + kvikkSort_cvalue);
		calculatedDurationNano = kvikkSort_cvalue * (128000 * (Math.log(128000)/Math.log(2)));
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		//Comparing fletteSort operation sizes
		System.out.println("--------------------------------------------------");
		System.out.println("FLETTESORTER");
		System.out.println("--------------------------------------------------");
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.fletteSorter(unsortedTable64000,0,unsortedTable64000.length-1);
			stopTimer();
			fletteSorter_result64000 = fletteSorter_result64000 + durationNano;
		}
		fletteSorter_result64000 = fletteSorter_result64000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average fletteSorter results for 64000:");
		System.out.println(fletteSorter_result64000/1000000000+" sec");
		System.out.println(fletteSorter_result64000/1000000+" ms");
		System.out.println(fletteSorter_result64000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(64000 * log2 64000)):");
		System.out.println("cvalue is " + fletteSorter_cvalue);
		
		calculatedDurationNano = fletteSorter_cvalue * (64000 * (Math.log(64000)/Math.log(2)));
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		for (int i=0; i<numberOfBaselineRuns;i++) {
			randomizeTables();
			startTimer();
			soking.fletteSorter(unsortedTable128000,0,unsortedTable128000.length-1);
			stopTimer();
			fletteSorter_result128000 = fletteSorter_result128000 + durationNano;
		}
		fletteSorter_result128000 = fletteSorter_result128000/numberOfBaselineRuns;
		System.out.println("---------------------");
		System.out.println("Actual average fletteSorter results for 128000:");
		System.out.println(fletteSorter_result128000/1000000000+" sec");
		System.out.println(fletteSorter_result128000/1000000+" ms");
		System.out.println(fletteSorter_result128000+" ns");
		System.out.println("---------------------");
		System.out.println("Expected calculated values (C*(128000 * log 128000)):");
		System.out.println("cvalue is " + fletteSorter_cvalue);
		calculatedDurationNano = fletteSorter_cvalue * (128000 * (Math.log(128000)/Math.log(2)));
		System.out.println(calculatedDurationNano/1000000000+" sec");
		System.out.println(calculatedDurationNano/1000000+" ms");
		System.out.println(calculatedDurationNano+" ns");
		System.out.println();
		
		System.out.println("PROGRAM END");
		
	}
	
	private static int randInt(int min, int max) {

	    // NOTE: Usually this should be a field rather than a method
	    // variable so that it is not re-seeded every call.
	    Random rand = new Random();

	    // nextInt is normally exclusive of the top value,
	    // so add 1 to make it inclusive
	    int randomNum = rand.nextInt((max - min) + 1) + min;

	    return randomNum;
	}
	
	private static void randomizeTables() {
		//filling tables with random Integer objects
//		System.out.println("Filling all tables with new random Integers");
		
		for (int i=0; i<unsortedTable20.length; i++) {
			unsortedTable20[i] = new Integer(randInt(0,999999));
		}
		
		for (int i=0; i<unsortedTable32000.length; i++) {
			unsortedTable32000[i] = new Integer(randInt(0,999999));
		}
		
		for (int i=0; i<unsortedTable64000.length; i++) {
			unsortedTable64000[i] = new Integer(randInt(0,999999));
		}
		
		for (int i=0; i<unsortedTable128000.length; i++) {
			unsortedTable128000[i] = new Integer(randInt(0,999999));
		}
	}
	
	private static void startTimer() {
		startTime = System.nanoTime();
	}
	
	private static void stopTimer() {
		endTime = System.nanoTime();
		durationNano = (endTime - startTime);
		durationMilli = durationNano/1000000;
		durationSec = durationMilli/1000;
		durationMin = durationSec/60;
		System.out.println("operation time: "+durationSec+ "sec");
		System.out.println("operation time: "+durationMilli+ "ms");
		System.out.println("operation time: "+durationNano+ "ns");
	}
	
	private static void printTable20() {
		if (doPrintouts) {
			System.out.println("Showing contents of unsortedTable20 after sorteringvedinnetting");
			for (int i=0; i<unsortedTable20.length; i++) {
				System.out.println(unsortedTable20[i]);
			}
		}

	}
	
	private static void printTable32000() {
		if (doPrintouts) {
			System.out.println("Showing contents of unsortedTable20 after sorteringvedinnetting");
			for (int i=0; i<unsortedTable32000.length; i++) {
				System.out.println(unsortedTable32000[i]);
			}
		}
	}
	
	private static void printTable64000() {
		if (doPrintouts) {
			System.out.println("Showing contents of unsortedTable20 after sorteringvedinnetting");
			for (int i=0; i<unsortedTable64000.length; i++) {
				System.out.println(unsortedTable64000[i]);
			}
		}
	}
	
	private static void printTable128000() {
		if (doPrintouts) {
			System.out.println("Showing contents of unsortedTable20 after sorteringvedinnetting");
			for (int i=0; i<unsortedTable128000.length; i++) {
				System.out.println(unsortedTable128000[i]);
			}
		}
	}

}
